package com.ankang.util;

import UHF.Reader18;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;

public class UHFTcpReaderTool {
    // 1. 全局变量优化：增加连接超时配置、原子变量确保线程安全
    private static final ReentrantLock DLL_GLOBAL_LOCK = new ReentrantLock(true); // 公平锁，避免线程饥饿
    private static final Set<Integer> ACTIVE_HANDLES = Collections.synchronizedSet(new HashSet<>());
    private static final Map<Integer, String> HANDLE_ADDRESS_MAP = new ConcurrentHashMap<>();
    private static final long LOCK_TIMEOUT = 3000; // 锁获取超时时间（3秒）
    private static final long CONNECTION_TIMEOUT = 5000; // 连接超时时间（5秒）
    private static final ScheduledExecutorService CLEAN_EXECUTOR = Executors.newSingleThreadScheduledExecutor();

    // 新增：跟踪端口的连接状态（是否已物理打开）
    private static final Map<String, AtomicBoolean> PORT_OCCUPIED_MAP = new ConcurrentHashMap<>();

    // 2. 实例变量优化：原子变量控制读取状态，增加连接时间戳
    private final Reader18 reader18 = new Reader18();
    private volatile int frameHandle = -1;
    private volatile int readerAddr = 0x00;
    private final String readerIp;
    private final int readerPort;
    private final AtomicBoolean isReading = new AtomicBoolean(false); // 原子变量，避免线程安全问题
    private final String addressKey;
    private volatile long lastActiveTime; // 最后活动时间戳，用于清理无效连接

    // 3. 静态初始化：启动定时清理任务
    static {
        try {
            String dllPath = "C:\\Windows\\System32\\UHF_Reader18.DLL";
            System.load(dllPath);
            System.out.println("✅ UHF_Reader18.DLL加载成功，路径：" + dllPath);

            // 定时清理无效连接（每30秒执行一次）
            CLEAN_EXECUTOR.scheduleAtFixedRate(
                    UHFTcpReaderTool::cleanInvalidConnections,
                    0,
                    30,
                    TimeUnit.SECONDS
            );
        } catch (UnsatisfiedLinkError e) {
            throw new RuntimeException("❌ DLL加载失败：" + e.getMessage());
        }
    }

    // 4. 构造方法（保持参数校验，增加时间戳初始化）
    public UHFTcpReaderTool(String readerIp, int readerPort) {
        if (readerIp == null || readerIp.trim().isEmpty()) {
            throw new IllegalArgumentException("❌ 读卡器IP不能为空（手册3.1.16节OpenNetPort参数要求）");
        }
        if (readerPort < 1024 || readerPort > 65535) {
            throw new IllegalArgumentException("❌ 端口必须在1024-65535（手册3.1.16节端口范围）");
        }
        this.readerIp = readerIp;
        this.readerPort = readerPort;
        this.addressKey = readerIp + ":" + readerPort;
        this.lastActiveTime = System.currentTimeMillis();
    }

    // 5. 核心方法优化：修复EPC读取配置，优化锁机制
    /**
     * 修复工作模式配置：确保读取EPC区（18000-6C协议）
     * 文档依据：手册3.1.12节SetWorkMode()函数参数规范
     */
    public boolean setWorkModeForTargetEpc() {
        if (!checkConnection()) {
            System.err.println("❌ 设置工作模式失败：连接失效");
            return false;
        }

        // 正确配置EPC区读取参数：18000-6C协议+EPC存储器+14字节（7字）
        int[] workModeParam = new int[8];
        workModeParam[0] = readerAddr;          // arr[0]：读写器真实地址（非0x00/0xFF）
        workModeParam[1] = 0x00;                // arr[1]：工作模式→应答模式（避免主动模式冲突）
        workModeParam[2] = 0x00;                // arr[2]：Mode_state→Bit2=0（18000-6C）+ Bit4=0（开蜂鸣）
        workModeParam[3] = 0x01;                // arr[3]：Mem_Inven→0x01（EPC存储器，手册3.1.12节）
        workModeParam[4] = 0x00;                // arr[4]：First_Adr→EPC区起始地址0
        workModeParam[5] = 0x07;                // arr[5]：Word_Num→7字=14字节（EPC标准长度，手册3.1.12节）
        workModeParam[6] = 0x00;                // arr[6]：主动模式间隔→应答模式下无效
        workModeParam[7] = frameHandle;         // arr[7]：网口句柄

        try {
            int result = reader18.SetWorkMode(workModeParam);
            if (result == 0) {
//                setPowerDbm(20); // 启用功率设置（20dBm，确保识别距离，手册3.1.8节）
                setScanTime(30); // 延长询查时间（3000ms，避免多标签时读取不完整，手册3.1.7节）
                System.out.println("✅ 工作模式设置成功：EPC区（14字节）+18000-6C协议+应答模式");
                return true;
            } else {
                System.err.println("❌ 设置工作模式失败（" + getErrorCodeMsg(result) + "，手册3.1.12节）");
                return false;
            }
        } catch (Exception e) {
            System.err.println("❌ 调用SetWorkMode()异常：" + e.getMessage());
            return false;
        }
    }

    /**
     * 连接方法优化：
     * 1. 使用公平锁+超时获取，避免多通道锁竞争卡死
     * 2. 加锁保护连接复用逻辑，解决并发安全问题
     * 3. 增加连接超时控制，避免无限阻塞
     */
    public boolean connect() {
        try {
            if (!DLL_GLOBAL_LOCK.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS)) {
                System.err.println("❌ 获取全局锁失败（超时" + LOCK_TIMEOUT + "ms）");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }

        try {
            cleanInvalidConnection();
            lastActiveTime = System.currentTimeMillis();

            // 检查端口是否已被占用
            AtomicBoolean isOccupied = PORT_OCCUPIED_MAP.computeIfAbsent(addressKey, k -> new AtomicBoolean(false));
            if (isOccupied.get()) {
                // 端口已被占用，尝试等待复用
                long startWait = System.currentTimeMillis();
                while (isOccupied.get()) {
                    if (System.currentTimeMillis() - startWait > CONNECTION_TIMEOUT) {
                        System.err.println("❌ 端口" + addressKey + "被占用，等待超时");
                        return false;
                    }
                    Thread.sleep(100); // 短轮询等待
                    // 检查是否已有可用句柄
                    for (Map.Entry<Integer, String> entry : HANDLE_ADDRESS_MAP.entrySet()) {
                        if (entry.getValue().equals(addressKey) && isHandleValid(entry.getKey())) {
                            this.frameHandle = entry.getKey();
                            this.readerAddr = getReaderAddress(frameHandle);
                            System.out.println("ℹ️ 复用连接：句柄" + frameHandle + "（" + addressKey + "）");
                            return true;
                        }
                    }
                }
            }

            // 尝试复用现有有效句柄
            for (Map.Entry<Integer, String> entry : HANDLE_ADDRESS_MAP.entrySet()) {
                if (entry.getValue().equals(addressKey)) {
                    int existingHandle = entry.getKey();
                    if (isHandleValid(existingHandle)) {
                        this.frameHandle = existingHandle;
                        this.readerAddr = getReaderAddress(existingHandle);
                        isOccupied.set(true); // 标记端口为占用状态
                        System.out.println("ℹ️ 复用连接：句柄" + frameHandle + "（" + addressKey + "）");
                        return true;
                    } else {
                        ACTIVE_HANDLES.remove(existingHandle);
                        HANDLE_ADDRESS_MAP.remove(existingHandle);
                        System.out.println("ℹ️ 清理无效复用句柄：" + existingHandle);
                    }
                }
            }

            // 新建连接（确保端口未被占用）
            isOccupied.set(true); // 预标记端口为占用状态
            int connectRetry = 0;
            while (connectRetry < 3) {
                long start = System.currentTimeMillis();
                int[] connectResult = reader18.OpenNetPort(0xFF, readerPort, readerIp);
                long cost = System.currentTimeMillis() - start;

                if (cost > CONNECTION_TIMEOUT) {
                    connectRetry++;
                    System.err.println("⚠️ 连接超时，第" + connectRetry + "次重试");
                    continue;
                }

                if (connectResult != null && connectResult.length >= 3) {
                    int resultCode = connectResult[0];
                    if (resultCode == 0 && connectResult[2] != -1) {
                        this.readerAddr = connectResult[1];
                        this.frameHandle = connectResult[2];
                        ACTIVE_HANDLES.add(frameHandle);
                        HANDLE_ADDRESS_MAP.put(frameHandle, addressKey);
                        System.out.println("✅ 连接成功：句柄" + frameHandle + "（" + addressKey + "）");
                        return true;
                    } else if (resultCode == 0x35) { // 错误码53：端口已打开
                        // 此时端口实际已被占用，释放预标记的占用状态
                        isOccupied.set(false);
                        System.err.println("❌ 连接失败：端口已被占用（错误码53）");
                        return false;
                    } else {
                        System.err.println("❌ 连接失败：" + getErrorCodeMsg(resultCode));
                        connectRetry++;
                        Thread.sleep(500);
                    }
                } else {
                    connectRetry++;
                    Thread.sleep(500);
                }
            }
            isOccupied.set(false); // 重试失败，释放占用标记
            return false;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            if (DLL_GLOBAL_LOCK.isHeldByCurrentThread()) {
                DLL_GLOBAL_LOCK.unlock();
            }
        }
    }

    /**
     * EPC读取方法优化：
     * 1. 修复EPC数据截取逻辑，确保读取完整14字节EPC
     * 2. 使用原子变量控制读取状态，避免多线程冲突
     * 3. 增加读取超时控制，避免通道卡死
     */
    public String readTargetEpc(int readCount, int readInterval) {
        // 参数校验
        if (readCount <= 0 || readInterval < 0) {
            System.err.println("❌ 参数错误：readCount必须>0，readInterval必须≥0");
            return null;
        }

        // 连接检查与自动重连
        if (!checkConnection()) {
            System.out.println("ℹ️ 连接失效，尝试自动重连");
            if (!connect()) {
                return null;
            }
        }

        Map<String, Integer> epcCountMap = new ConcurrentHashMap<>();
        isReading.set(true);
        long readTimeout = readCount * (readInterval + 100); // 读取总超时（预留100ms/次处理时间）
        long startReadTime = System.currentTimeMillis();

        try {
            for (int i = 0; i < readCount && isReading.get(); i++) {
                // 读取总超时判断
                if (System.currentTimeMillis() - startReadTime > readTimeout) {
                    System.err.println("❌ 读取超时（总耗时" + (System.currentTimeMillis() - startReadTime) + "ms）");
                    break;
                }

                try {
                    String currentEpc = inventoryG2ExtractTargetEpc();
                    if (currentEpc != null && !currentEpc.isEmpty()) {
                        epcCountMap.put(currentEpc, epcCountMap.getOrDefault(currentEpc, 0) + 1);
                        lastActiveTime = System.currentTimeMillis(); // 更新活动时间
                    }

                    // 间隔控制（最后一次不等待）
                    if (i < readCount - 1 && readInterval > 0) {
                        Thread.sleep(readInterval);
                    }
                } catch (Exception e) {
                    System.err.println("⚠️ 第" + (i + 1) + "次询查异常：" + e.getMessage());
                    // 重连后继续读取（最多重连1次）
                    if (connect()) {
                        continue;
                    } else {
                        break;
                    }
                }
            }
        } finally {
            isReading.set(false); // 确保读取状态重置
        }

        // 返回读取次数最多的EPC（避免偶然错误）
        return epcCountMap.entrySet().stream()
                .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
                .map(Map.Entry::getKey)
                .findFirst()
                .orElse(null);
    }

    /**
     * 修复EPC数据提取逻辑：
     * 文档依据：手册3.2.1节，Inventory_G2()返回数组第3位开始为EPC数据，长度14字节
     */
    private String inventoryG2ExtractTargetEpc() {
        if (!checkConnection()) {
            System.err.println("❌ 询查失败：连接失效（手册3.2.1节）");
            return null;
        }

        // 手册3.2.1节：Inventory_G2()输入参数为[读写器地址, 网口句柄]
        int[] inventoryParam = new int[]{readerAddr, frameHandle};
        try {
            int[] inventoryResult = reader18.Inventory_G2(inventoryParam);

            // 1. 基础校验：至少包含“结果码+标签数+EPC长度”3字节（手册3.2.1节）
            if (inventoryResult == null || inventoryResult.length < 3) {
                System.err.println("❌ 询查失败：数据不完整（手册3.2.1节需至少3字节基础信息）");
                return null;
            }

            // 2. 提取手册定义的核心字段（索引严格对应手册）
            int resultCode = inventoryResult[0];    // 索引0：执行结果码
            int tagCount = inventoryResult[1];      // 索引1：标签数量（单标签需为1）
            int epcByteLength = inventoryResult[2]; // 索引2：EPC实际字节长度（关键！）

            // 3. 单标签校验（手册3.2.1节：单标签场景tagCount=1）
            if (tagCount != 1) {
                System.err.println("❌ 标签数量异常（手册3.2.1节单标签需返回1，实际" + tagCount + "）");
                return null;
            }

            // 4. EPC数据完整性校验（总长度≥3+epcByteLength，手册3.2.1节）
            if (inventoryResult.length < 3 + epcByteLength) {
                System.err.println("❌ EPC数据不完整（手册3.2.1节需" + (3 + epcByteLength) + "字节，实际" + inventoryResult.length + "字节）");
                return null;
            }


            int[] epcBytes = Arrays.copyOfRange(inventoryResult, 3, 3 + 14);
            String epcHex = bytesToHex(epcBytes);
            return epcHex.length() == 28 ? epcHex.substring(2, 26) : null;

        } catch (Exception e) {
            System.err.println("❌ 询查异常（手册3.2.1节）：" + e.getMessage());
            this.frameHandle = -1;
            return null;
        }
    }

    /**
     * 断开连接方法优化：确保资源释放，避免句柄泄漏
     */
    public void disconnect() {
        if (frameHandle == -1) {
            System.out.println("ℹ️ 无需断开：句柄已无效");
            return;
        }

        try {
            if (DLL_GLOBAL_LOCK.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS)) {
                try {
                    if (ACTIVE_HANDLES.contains(frameHandle)) {
                        reader18.CloseNetPort(frameHandle);
                        System.out.println("✅ 断开连接：句柄" + frameHandle);
                    }
                    // 清理全局资源
                    ACTIVE_HANDLES.remove(frameHandle);
                    HANDLE_ADDRESS_MAP.remove(frameHandle);
                    // 释放端口占用状态
                    PORT_OCCUPIED_MAP.remove(addressKey);
                    // 重置实例状态
                    this.frameHandle = -1;
                    this.readerAddr = 0x00;
                    this.lastActiveTime = 0;
                } catch (Exception e) {
                    System.err.println("❌ 断开异常：" + e.getMessage());
                } finally {
                    DLL_GLOBAL_LOCK.unlock();
                }
            } else {
                System.err.println("❌ 获取锁失败，无法安全断开连接");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    // 6. 辅助方法优化
    /**
     * 功率设置（手册3.1.8节）：确保功率在0~30dBm范围
     */
    private void setPowerDbm(int power) {
        if (!checkConnection()) return;
        // 功率范围校验（手册3.1.8节：0~30dBm）
        power = Math.max(0, Math.min(30, power));
        int[] powerParam = new int[]{this.readerAddr, power, this.frameHandle};

        try {
            int result = reader18.SetPowerDbm(powerParam);
            if (result == 0) {
                System.out.println("✅ 功率设置成功（手册3.1.8节）：" + power + "dBm");
            } else {
                System.err.println("❌ 功率设置失败（" + getErrorCodeMsg(result) + "，手册3.1.8节）");
            }
        } catch (Exception e) {
            System.err.println("❌ 调用SetPowerDbm()异常：" + e.getMessage());
        }
    }

    /**
     * 询查时间设置（手册3.1.7节）：确保时间在3~255*100ms范围
     */
    private void setScanTime(int scanTime) {
        if (!checkConnection()) {
            System.err.println("❌ 延长询查时间失败：连接失效");
            return;
        }
        // 询查时间范围校验（手册3.1.7节：3~255*100ms）
        scanTime = Math.max(3, Math.min(255, scanTime));
        int[] scanTimeParam = new int[]{this.readerAddr, scanTime, this.frameHandle};

        try {
            int result = reader18.WriteScanTime(scanTimeParam);
            if (result == 0) {
                System.out.println("✅ 询查时间设置成功（手册3.1.7节）：" + scanTime * 100 + "ms");
            } else {
                System.err.println("❌ 询查时间设置失败（" + getErrorCodeMsg(result) + "，手册3.1.7节）");
            }
        } catch (Exception e) {
            System.err.println("❌ 调用WriteScanTime()异常：" + e.getMessage());
        }
    }

    /**
     * 连接检查优化：增加活动时间校验，避免僵尸连接
     */
    private boolean checkConnection() {
        // 句柄无效直接返回
        if (frameHandle == -1 || !ACTIVE_HANDLES.contains(frameHandle)) {
            return false;
        }

        // 检查连接是否超时（10秒无活动视为无效）
        if (System.currentTimeMillis() - lastActiveTime > 10000) {
            System.err.println("❌ 连接超时（10秒无活动）");
            return false;
        }

        // 硬件连接校验（手册3.1.5节）
        try {
            int[] infoParam = new int[]{readerAddr, frameHandle};
            int[] infoResult = reader18.GetReaderInformation(infoParam);
            // 有效连接需满足：结果非空+长度≥9+状态码0（手册3.1.5节）
            boolean isValid = infoResult != null && infoResult.length >= 9 && infoResult[0] == 0;
            if (!isValid) {
                this.frameHandle = -1; // 标记无效句柄
            }
            return isValid;
        } catch (Exception e) {
            this.frameHandle = -1;
            return false;
        }
    }

    /**
     * 句柄有效性校验（手册3.1.5节）
     */
    private boolean isHandleValid(int handle) {
        try {
            int[] infoParam = new int[]{0xFF, handle};
            int[] infoResult = reader18.GetReaderInformation(infoParam);
            // 有效句柄需满足：结果非空+长度≥9+状态码0+设备类型0x09（手册3.1.5节）
            return infoResult != null && infoResult.length >= 9 && infoResult[0] == 0 && infoResult[3] == 0x09;
        } catch (Exception e) {
            System.err.println("⚠️ 校验句柄" + handle + "有效性异常：" + e.getMessage());
            return false;
        }
    }

    /**
     * 清理当前实例的无效连接
     */
    private void cleanInvalidConnection() {
        if (frameHandle != -1 && !isHandleValid(frameHandle)) {
            try {
                reader18.CloseNetPort(frameHandle);
            } catch (Exception e) {
                System.err.println("⚠️ 清理无效句柄" + frameHandle + "异常：" + e.getMessage());
            } finally {
                ACTIVE_HANDLES.remove(frameHandle);
                HANDLE_ADDRESS_MAP.remove(frameHandle);
                this.frameHandle = -1;
                this.readerAddr = 0x00;
            }
        }
    }

    /**
     * 静态方法：清理所有无效连接（定时任务调用）
     */
    private static void cleanInvalidConnections() {
        if (DLL_GLOBAL_LOCK.tryLock()) {
            try {
                List<Integer> invalidHandles = new ArrayList<>();
                for (int handle : ACTIVE_HANDLES) {
                    try {
                        int[] infoParam = new int[]{0xFF, handle};
                        int[] infoResult = new Reader18().GetReaderInformation(infoParam);
                        if (infoResult == null || infoResult.length < 9 || infoResult[0] != 0 || infoResult[3] != 0x09) {
                            invalidHandles.add(handle);
                        }
                    } catch (Exception e) {
                        invalidHandles.add(handle);
                    }
                }

                Reader18 tempReader = new Reader18();
                for (int invalidHandle : invalidHandles) {
                    try {
                        tempReader.CloseNetPort(invalidHandle);
                    } catch (Exception e) {
                        System.err.println("⚠️ 关闭无效句柄异常：" + e.getMessage());
                    } finally {
                        String addrKey = HANDLE_ADDRESS_MAP.get(invalidHandle);
                        if (addrKey != null) {
                            PORT_OCCUPIED_MAP.remove(addrKey); // 同步释放端口占用
                        }
                        ACTIVE_HANDLES.remove(invalidHandle);
                        HANDLE_ADDRESS_MAP.remove(invalidHandle);
                        System.out.println("ℹ️ 全局清理无效连接：句柄" + invalidHandle);
                    }
                }
            } finally {
                DLL_GLOBAL_LOCK.unlock();
            }
        }
    }

    /**
     * 获取读写器地址（手册3.1.5节）
     */
    private int getReaderAddress(int handle) {
        try {
            int[] infoParam = new int[]{0xFF, handle};
            int[] infoResult = reader18.GetReaderInformation(infoParam);
            // 手册3.1.5节：第4个字节为设备类型，第2-3字节为版本，第1字节为状态
            if (infoResult != null && infoResult.length >= 9 && infoResult[0] == 0) {
                return infoResult[1]; // 第2个字节为读写器地址（手册3.1.5节返回参数定义）
            }
            return 0x00;
        } catch (Exception e) {
            System.err.println("⚠️ 获取读写器地址异常：" + e.getMessage());
            return 0x00;
        }
    }

    /**
     * 错误码解析（手册4.其他返回值定义+5.错误代码定义）
     */
    private String getErrorCodeMsg(int resultCode) {
        return switch (resultCode) {
            case 0x30 -> "错误码48：通讯错误（手册4.其他返回值定义）";
            case 0x31 -> "错误码49：CRC校验错误（手册4.其他返回值定义）";
            case 0x32 -> "错误码50：返回数据长度错误（手册4.其他返回值定义）";
            case 0x33 -> "错误码51：通讯繁忙（手册4.其他返回值定义）";
            case 0x34 -> "错误码52：指令正在执行（手册4.其他返回值定义）";
            case 0x35 -> "错误码53：端口已打开（手册4.其他返回值定义）";
            case 0x36 -> "错误码54：端口已关闭（手册4.其他返回值定义）";
            case 0x37 -> "错误码55：无效句柄（手册4.其他返回值定义）";
            case 0x38 -> "错误码56：无效端口（手册4.其他返回值定义）";
            case 0xFB -> "错误码251：无电子标签可操作（手册4.其他返回值定义）";
            case 0xFF -> "错误码255：参数错误（手册4.其他返回值定义）";
            case 0x05 -> "错误码5：访问密码错误（手册4.其他返回值定义）";
            case 0x0B -> "错误码11：电子标签不支持该命令（手册4.其他返回值定义）";
            case 0x10 -> "错误码16：有字节空间被锁定，写入失败（手册4.其他返回值定义）";
            case 0x00 -> "错误码0：其它错误（手册5.错误代码定义）";
            case 0x03 -> "错误码3：存储器超限或不被支持的PC值（手册5.错误代码定义）";
            case 0x04 -> "错误码4：存储器锁定（手册5.错误代码定义）";
            default -> "未知错误码" + resultCode + "（对照手册4.其他返回值定义+5.错误代码定义）";
        };
    }

    /**
     * 字节数组转16进制字符串（确保EPC格式正确）
     */
    private String bytesToHex(int[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        StringBuilder hexBuilder = new StringBuilder();
        for (int b : bytes) {
            hexBuilder.append(String.format("%02X", b & 0xFF));
        }
        return hexBuilder.toString();
    }

    /**
     * 停止读取（用于紧急中断，避免通道卡死）
     */
    public void stopReading() {
        isReading.set(false);
        System.out.println("ℹ️ 已停止读取操作");
    }

    /**
     * 销毁资源（用于JVM退出时清理）
     */
    public static void destroy() {
        CLEAN_EXECUTOR.shutdown();
        try {
            if (!CLEAN_EXECUTOR.awaitTermination(5, TimeUnit.SECONDS)) {
                CLEAN_EXECUTOR.shutdownNow();
            }
        } catch (InterruptedException e) {
            CLEAN_EXECUTOR.shutdownNow();
        }
        System.out.println("✅ 资源清理完成");
    }
}